#include "serial.h"
#include "ui_serial.h"
#include <QTypeInfo>
#include <QMessageBox>
#include "modbuscrc.h"
#include "typeconver.h"
#include <qdesktopservices.h>
using namespace std;

/*------------------------------------------报警灯形状、颜色-----------------------------------------------*/
const QString red_SheetStyle   = "min-width: 48px; min-height: 48px;max-width:48px; max-height: 48px;border-radius: 24px;  border:1px solid black;background:red";
const QString green_SheetStyle = "min-width: 48px; min-height: 48px;max-width:48px; max-height: 48px;border-radius: 24px;  border:1px solid black;background:rgb(0,255,0)";
const QString grey_SheetStyle   = "min-width: 48px; min-height: 16px;max-width:16px; max-height: 16px;border-radius: 8px;  border:1px solid black;background:grey";
const QString yellow_SheetStyle = "min-width: 48px; min-height: 16px;max-width:16px; max-height: 16px;border-radius: 8px;  border:1px solid black;background:yellow";
/*------------------------------------------------------------------------------------------------------*/

ConfigData defaultConfigData={  //配置参数默认值
    "COM1", 9600 , 8, "none", 1
};
ConfigData configData;  //配置参数

Serial *Serial::serialClass = nullptr; //初始化

Serial::Serial(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Serial)
{
    ui->setupUi(this);

    serialClass = this;    //赋值,用于charttable.cpp和chartfigure.cpp

    this->setWindowFlags(windowFlags()& ~Qt::WindowMaximizeButtonHint); //设置窗口大小锁定
    this->setFixedSize(this->width(), this->height());              //设置窗口大小
    //this->setStyleSheet("background-color:rgb(255, 249, 225);");  //修改窗口默认背景色

    figure = new ChartFigure(this); //曲线图表
    table = new ChartTable(this);   //表格
    ui->chartArea->setWidget(figure);
    ui->tableArea->setWidget(table);

    lb_tips = new QLabel(); //左下角信息提示框
    path = new QDir(QDir::currentPath()); //读取当前路径 QDir类
    curPath = QDir::currentPath();        //读取当前应用程序路径 QString类
    currentTime = QDateTime::currentDateTime();   //获取当前系统时间
    system_init();     //系统初始化
    loadConfigData();  //加载配置参数，并根据参数显示界面

    /*---------------------------菜单栏设计信号与槽(Begin)-------------------------------------*/
    connect(ui->m1_exit, SIGNAL(triggered()), this, SLOT(menu_exit_click()));               //退出
    connect(ui->m2_open_temp_fold, SIGNAL(triggered()), this, SLOT(menu_open_temp_fold())); //打开临时文件夹
    connect(ui->m2_open_log_fold, SIGNAL(triggered()), this, SLOT(menu_open_log_fold()));   //打开日志文件夹
    connect(ui->m2_open_log_file, SIGNAL(triggered()), this, SLOT(menu_open_log_file()));   //打开日志文件
    connect(ui->m1_company_about, SIGNAL(triggered()), this, SLOT(menu_company_about()));   //打开公司简介
    connect(ui->m1_company_web, SIGNAL(triggered()), this, SLOT(menu_company_web()));       //打开公司官网
    connect(ui->m1_about, SIGNAL(triggered()), this, SLOT(menu_about_click()));             //打开关于
    connect(ui->m2_mlmin, SIGNAL(triggered()), this, SLOT(menu_unit_flow_ML()));            //流量单位ML/MIN
    connect(ui->m2_LH, SIGNAL(triggered()), this, SLOT(menu_unit_flow_L()));                //流量单位L/H
    connect(ui->m2_ssd, SIGNAL(triggered()), this, SLOT(menu_unit_temper_SSD()));           //温度单位℃
    connect(ui->m2_hsd, SIGNAL(triggered()), this, SLOT(menu_unit_temper_HSD()));           //温度单位℉
    /*---------------------------菜单栏设计信号与槽(End)-------------------------------------*/

    /*-------------------------------------------槽函数(按钮事件)------------------------------------------*/
    connect(ui->btn_OpenSerial , &QPushButton::clicked, this, &Serial::btn_OpenSerial_clicked);   //打开串口
    connect(ui->btn_CloseSerial, &QPushButton::clicked, this, &Serial::btn_CloseSerial_clicked);  //关闭串口
    connect(ui->btn_ScanSerial , &QPushButton::clicked, this, &Serial::btn_ScanSerial_clicked);   //串口扫描

    connect(ui->btn_temper_save_data,&QPushButton::clicked, this, &Serial::save_temperDataTo_file);//保存温度数据
    connect(ui->btn_flow_save_data,  &QPushButton::clicked, this, &Serial::save_flowDataTo_file);  //保存流量数据
    connect(ui->btn_setTemper_upper,  &QPushButton::clicked, this, &Serial::set_temper_upper);     //设置温度安全上限
    connect(ui->btn_setTemper_lower,  &QPushButton::clicked, this, &Serial::set_temper_lower);     //设置温度安全下限
    connect(ui->btn_setFlow_upper,  &QPushButton::clicked, this, &Serial::set_flow_upper);         //设置流量安全上限
    connect(ui->btn_setFlow_lower,  &QPushButton::clicked, this, &Serial::set_flow_lower);         //设置流量安全下限
    connect(ui->btn_temper_history_data,  &QPushButton::clicked, this, &Serial::query_temperData_history);//查看温度历史数据
    connect(ui->btn_flow_history_data,  &QPushButton::clicked, this, &Serial::query_flowData_history);    //查看流量历史数据

    connect(ui->btn_reset_sys, &QPushButton::clicked, this, &Serial::reset_system); //系统复位

    connect(ui->btn_temper_warning_reset, &QPushButton::clicked, this, &Serial::btn_reset_temper_alarm);//温度报警复位
    connect(ui->btn_flow_warning_reset, &QPushButton::clicked, this, &Serial::btn_reset_flow_alarm);    //流量报警复位
    connect(ui->btn_warning_reset, &QPushButton::clicked, this, &Serial::btn_reset_allParam_alarm);     //报警复位

    connect(ui->btn_save_log,&QPushButton::clicked, this, &Serial::btn_save_log);       //保存日志
    connect(ui->btn_clear_log,&QPushButton::clicked, this, &Serial::btn_clear_log);     //清除日志

    connect(ui->btn_setSlaveAddr, &QPushButton::clicked, this, &Serial::btn_set_slave_addr);   //修改从机地址

    connect(ui->btn_setSerial_param, &QPushButton::clicked, this, &Serial::btn_set_serial_param);   //修改modbus串口连接参数
    connect(ui->btn_Serial_back, &QPushButton::clicked, this, &Serial::btn_back_serial_param);      //还原modbus串口连接参数
    connect(ui->btn_safe_limit_param_back, &QPushButton::clicked, this, &Serial::btn_back_safe_limit_param);   //还原数据安全上下限参数
    /*----------------------------------------------------------------------------------------------------*/

    /*---------------------------------------------槽函数(定时器)-------------------------------------------*/
    connect(&datetime_clock, SIGNAL(timeout()), this, SLOT(lb_getDateTime()));  //更新系统时间定时器
    connect(&send_cmd_timer, SIGNAL(timeout()), this, SLOT(auto_send_recv_data())); //发送数据帧定时器
    /*----------------------------------------------------------------------------------------------------*/
}

Serial::~Serial()
{
    delete ui;
}


/**
 * @brief 系统复位
 */
void Serial::reset_system()
{
    QMessageBox *msgbox = new QMessageBox;
    msgboxcreate(msgbox, "提示", "确定要恢复默认值吗？", 1);
    int ret = msgbox->exec();
    if(ret == QMessageBox::Ok){
        //恢复默认值所作的操作
    }
}

/**
 * @brief 系统初始化函数 按钮、图表等默认状态
 */
void Serial::system_init()
{
    iniFilePath = QCoreApplication::applicationDirPath()+"/config.ini";     //读取配置文件的路径
    settings = new QSettings(iniFilePath, QSettings::IniFormat);            //读取配置文件
    settings->setIniCodec(QTextCodec::codecForName("GB2312"));              //设置读写配置文件的编码格式
    this->setWindowTitle(settings->value("ExeTitle/EXE_TITLE").toString()); //修改左上角标题
    ui->btn_CloseSerial->setDisabled(1);        //打开串口之前锁定关闭串口按钮

    ui->btn_temper_save_data->setDisabled(1);   //设置温保存度数据不可操作
    ui->btn_flow_save_data->setDisabled(1);     //设置保存流量数据不可操作
    ui->btn_temper_history_data->setDisabled(1);//设置查看温度历史数据不可操作
    ui->btn_flow_history_data->setDisabled(1);  //设置查看流量历史数据不可操作

    ui->le_Lower_temper->setEnabled(false);     //设置温度下限显示框不可编辑
    ui->le_Upper_temper->setEnabled(false);     //设置温度上限显示框不可编辑
    ui->le_Upper_flow->setEnabled(false);       //设置流量上限显示框不可编辑
    ui->le_Lower_flow->setEnabled(false);       //设置流量下限显示框不可编辑
    ui->le_Upper_flow->setStyleSheet("color:blue");     //设置流量上限显示蓝色
    ui->le_Lower_flow->setStyleSheet("color:blue");     //设置流量下限显示蓝色
    ui->le_Upper_temper->setStyleSheet("color:blue");   //设置温度上限显示蓝色
    ui->le_Lower_temper->setStyleSheet("color:blue");   //设置温度下限显示蓝色

    ui->le_slave_addr->setText(settings->value("SlaveAddr/SLAVEADDR").toString());   //读取配置文件中的从机地址
    ui->le_slave_addr->setDisabled(1);              //从机地址显示区设置不可编辑
    ui->le_slave_addr->setStyleSheet("color:blue"); //设置从机地址显示蓝色
    ui->btn_setSlaveAddr->setDisabled(1);           //设置新地址不可操作

    ui->btn_setSerial_param->setDisabled(1);        //modbus串口连接参数设置按钮不可操作
    ui->btn_Serial_back->setDisabled(1);            //modbus串口连接参数还原按钮不可操作

    obj_resetFlag.reset_temper = false; //温度报警复位标志位失效
    obj_resetFlag.reset_flow = false;   //流量报警复位标志位失效

    ui->lb_unit_temper->setText("℃");   //温度上限处默认单位摄氏度
    ui->lb_unit_temper1->setText("℃");  //温度下限处默认单位摄氏度
    ui->lb_unit_flow->setText("ml/min"); //流量上限处默认单位ml/min
    ui->lb_unit_flow1->setText("ml/min");//流量下限处默认单位ml/min

    ui->m2_LH->setIconVisibleInMenu(false);     //菜单栏L/H选中图标不显示
    ui->m2_hsd->setIconVisibleInMenu(false);    //菜单栏华氏度选中图标不显示

    obj_param.flow_f = 0;       //温度数据初始化为0
    obj_param.temper_f = 0;     //流量数据初始化为0

    cmd_init_ready();   //初始化问询数据帧
    datetime_clock.start(1000); //系统时间显示更新定时器启动
    file_fold_init();   //创建临时文件夹以及临时文件存储实时数据
}



/**
 * @brief 初始化发送命令
 */
void Serial::cmd_init_ready()
{
    obj_send_crcCal_tf.old_addr = ui->le_slave_addr->text();  //地址码
    obj_send_crcCal_tf.func_read_data = "03";     //功能码，读数据寄存器
    obj_send_crcCal_tf.start_addr[0] = "00";
    obj_send_crcCal_tf.start_addr[1] = "00";    //读取的寄存器起始地址
    obj_send_crcCal_tf.data_len[0] = "00";
    obj_send_crcCal_tf.data_len[1] = "02";      //接收参数个数（2个：温度流量   共4字节）
    //计算CRC校验值
    obj_send_crcCal_tf.crc = crcCalculation(obj_send_crcCal_tf.old_addr+
                                            obj_send_crcCal_tf.func_read_data+
                                            obj_send_crcCal_tf.start_addr[0]+
                                            obj_send_crcCal_tf.start_addr[1]+
                                            obj_send_crcCal_tf.data_len[0]+
                                            obj_send_crcCal_tf.data_len[1]);
}

/**
 * @brief 临时文件（夹）初始化
 */
void Serial::file_fold_init()
{
    //创建临时文件夹以及临时文件存储实时数据
    bool exist = path->exists("temp");     //判断当前路径下是否存在此文件夹
    if(!exist){path->mkdir("temp");}       //不存在则创建此文件夹

    QFile tempfile1("temp/temper.txt");
    if(tempfile1.open(QFile::WriteOnly)){  //以写的方式创建打开存储数据的文件
        QTextStream out(&tempfile1);       //写入数据到文本文件中
        out<<"\tdatetime\t\tdata\t\tUpper\t\tLower\t\tstatus"<<endl;
    }
    tempfile1.close(); //关闭文件

    QFile tempfile2("temp/flow.txt");
    if(tempfile2.open(QFile::WriteOnly)){            //以写的方式创建打开存储数据的文件
        QTextStream out(&tempfile2);                 //写入数据到文本文件中
        out<<"\tdatetime\t\tdata\t\tUpper\t\tLower\t\tstatus"<<endl;
    }
    tempfile2.close(); //关闭文件
}
/**
 * @brief 插拔串口之后手动扫描串口设备
 */
void Serial::btn_ScanSerial_clicked()
{
    getSerialPort();    //扫描串口
    show_tips("串口扫描完成!");
    print_log("串口扫描完毕", 0);
}

/**
 * @brief 更新系统时间
 */
void Serial::lb_getDateTime()
{
    QDateTime current_date_time =QDateTime::currentDateTime();  //获取当前时间
    ui->lb_datetime->setText(current_date_time.toString("yyyy-MM-dd  hh:mm:ss"));//设置时间格式
}

/**
 * @brief 系统定时发送发送数据帧请求接收数据
 *        连续10次（10s）接收空数据帧判定从机掉线，进行软件弹框提示
 *        同时判断串口是否连接正常
 */
void Serial::auto_send_recv_data()
{
    static int saveCount = 0;  //用于检查发送闻讯帧接收到的数据帧是否连续多次为空

    getSerialPort();    //此处获取串口信息会刷新当前连接的串口显示
    auto_alarm_check(); //自动报警检测
    ////拼接发送命令
    obj_cmd.cmd = obj_send_crcCal_tf.old_addr+
            obj_send_crcCal_tf.func_read_data+
            obj_send_crcCal_tf.start_addr[0]+
            obj_send_crcCal_tf.start_addr[1]+
            obj_send_crcCal_tf.data_len[0]+
            obj_send_crcCal_tf.data_len[1]+
            obj_send_crcCal_tf.crc;
    //QString cmd = obj_send_crcCal_tf.old_addr+obj_send_crcCal_tf.func_read_data+obj_send_crcCal_tf.start_addr[0]+obj_send_crcCal_tf.start_addr[1]+obj_send_crcCal_tf.data_len[0]+obj_send_crcCal_tf.data_len[1]+obj_send_crcCal_tf.crc;
    //qDebug()<<"write::::"<<global_port.write(QString2Hex(obj_cmd.cmd.toLatin1())); //写命令
    global_port.write(QString2Hex(obj_cmd.cmd.toLatin1())); //写命令
    global_port.flush();    //不加载到缓冲区，及时写入命令
    QByteArray array = global_port.readAll();

    try {
        if(array.length() == 0){    //接收到的数据帧为0是抛出异常
            saveCount += 1;
            throw("recv cmd is null!");
        }else{
            table->insert_item(obj_param.temper_f, obj_param.flow_f, ui);      //有数据时表格插入数据
            figure->DrawLine(QDateTime::currentDateTime().toMSecsSinceEpoch(), obj_param.temper_f, obj_param.flow_f);
        }
    } catch (const char* msg) { //接收到抛出的异常时直接退出本次接收的数据帧的处理
        qDebug()<<msg<< "error count:"<<saveCount;
        if(saveCount >= 10){  //大于十次接收的数据帧为空，进行提示，同时复位报警信息(当前数据归零则复位报警)，清空lcd面板
            QMessageBox *msgbox = new QMessageBox;
            msgboxcreate(msgbox, "提示", "<font color='red'>获取数据失败，请检查及时设备连接状态！</font>", 2);
            msgbox->exec();

            obj_param.flow_f = 0;
            obj_param.temper_f = 0;
            ui->lcd_FlowValue->display(0);
            ui->lcd_TemperValue->display(0);
            saveCount = 0;
        }
        return;
    }

    saveCount = 0;
    ArraySplit(array);      //分割流量和温度

    //qDebug()<<array.length()<<"t_send: "<<obj_cmd.cmd<<"\t t_recv: "<<obj_param.temper_f<<"\t f_recv: "<<obj_param.flow_f<<"\tsize:"<<array.size();
    //qDebug()<<"cmd_send: "<<obj_cmd.cmd<<"\tcmd_recv: "<<array<<"cmd_recv_length: "<<array.length()<<"\t t_recv: "<<obj_param.temper_f<<"\t f_recv: "<<obj_param.flow_f;

    ui->lcd_TemperValue->setDigitCount(6);  //数码管数字显示位数
    ui->lcd_TemperValue->setStyleSheet("background-color: yellow"); //读取到数字之后的背景色
    if(unit_temper_ssd){    //温度单位切换
        ui->lcd_TemperValue->display(obj_param.temper_f);               //温度数值显示到数码管上(摄氏度)
    }else{
        ui->lcd_TemperValue->display(32+obj_param.temper_f*1.8);        //温度数值显示到数码管上(华氏度)
    }


    ui->lcd_FlowValue->setDigitCount(6);
    ui->lcd_FlowValue->setStyleSheet("background-color: yellow");
    if(unit_flow_ml){    //流量单位切换
        ui->lcd_FlowValue->display(obj_param.flow_f);
    }else{
        ui->lcd_FlowValue->display(obj_param.flow_f*0.06);
    }

    /*--------------------------实时数据追加到临时文件(Begin)---------------------------------------*/
    QFile tempfile1("temp/temper.txt");

    QTextCodec *codec = QTextCodec::codecForName("GB2312");//或者"GBK",不分大小写
    QTextCodec::setCodecForLocale(codec);

    tempfile1.open(QIODevice::ReadWrite | QIODevice::Append);    //以读写切追加写入的方式操作文本
    QTextStream dataWrite1(&tempfile1);
    if(obj_param.temper_f > obj_safe_scope.temper_upper){
        dataWrite1<<ui->lb_datetime->text()<<"\t\t"
                  <<obj_param.temper_f<<tr("℃")<<"\t\t"
                  <<obj_safe_scope.temper_upper<<tr("℃")<<"\t\t"
                  <<obj_safe_scope.temper_lower<<tr("℃")<<"\t\tOverHigh\t"<<endl;
    }else if(obj_param.temper_f < obj_safe_scope.temper_lower){
        dataWrite1<<ui->lb_datetime->text()<<"\t\t"
                  <<obj_param.temper_f<<tr("℃")<<"\t\t"
                  <<obj_safe_scope.temper_upper<<tr("℃")<<"\t\t"
                  <<obj_safe_scope.temper_lower<<tr("℃")<<"\t\tOverLow\t"<<endl;
    }else{
        dataWrite1<<ui->lb_datetime->text()<<"\t\t"
                  <<obj_param.temper_f<<tr("℃")<<"\t\t"
                  <<obj_safe_scope.temper_upper<<tr("℃")<<"\t\t"
                  <<obj_safe_scope.temper_lower<<tr("℃")<<"\t\tSafe\t"<<endl;
    }
    tempfile1.close();

    QFile tempfile2("temp/flow.txt");
    tempfile2.open(QIODevice::ReadWrite | QIODevice::Append);
    QTextStream dataWrite2(&tempfile2);
    if(obj_param.flow_f > obj_safe_scope.flow_upper){
        dataWrite2<<ui->lb_datetime->text()<<"\t\t"
                  <<obj_param.flow_f<<tr("ml/min")<<"\t\t"
                  <<obj_safe_scope.flow_upper<<tr("ml/min")<<"\t\t"
                  <<obj_safe_scope.flow_lower<<tr("ml/min")<<"\t\tOverHigh\t"<<endl;
    }else if(obj_param.flow_f < obj_safe_scope.flow_lower){
        dataWrite2<<ui->lb_datetime->text()<<"\t\t"
                  <<obj_param.flow_f<<tr("ml/min")<<"\t\t"
                  <<obj_safe_scope.flow_upper<<tr("ml/min")<<"\t\t"
                  <<obj_safe_scope.flow_lower<<tr("ml/min")<<"\t\tOverLow\t"<<endl;
    }else{
        dataWrite2<<ui->lb_datetime->text()<<"\t\t"
                  <<obj_param.flow_f<<tr("ml/min")<<"\t\t"
                  <<obj_safe_scope.flow_upper<<tr("ml/min")<<"\t\t"
                  <<obj_safe_scope.flow_lower<<tr("ml/min")<<"\t\tSafe\t"<<endl;
    }
    tempfile2.close();
    /*--------------------------实时数据追加到临时文件(End)------------------------------------------*/
}

/**
 * @brief 保存温度数据到指定文件
 */
void Serial::save_temperDataTo_file()
{
    QString dlgTitle="Choose Save Directory";   //title
    QString savedir = QFileDialog::getExistingDirectory(this,dlgTitle,curPath,QFileDialog::ShowDirsOnly
                                                     | QFileDialog::DontResolveSymlinks);

    if(savedir.length() != 0){
        QString tempfilename = curPath+"/temp/temper.txt";
        QString savefilename = savedir+settings->value("DataSave/TEMPERFILENAME").toString();
        obj_datafile_path.temperpath = savefilename;
        QFile savefile(savefilename);
        if(savefile.exists()){  //若之前已经存在此文件，则先删除此文件
            savefile.remove();
        }
        QFile tempfile(tempfilename);
        if(tempfile.copy(savefilename)){
            show_tips("成功保存温度数据至"+savedir+settings->value("DataSave/TEMPERFILENAME").toString());
            print_log("成功保存温度数据至"+savedir+settings->value("DataSave/TEMPERFILENAME").toString(), 0);
        }
    }
}

/**
 * @brief 保存流量数据到指定文件
 */
void Serial::save_flowDataTo_file()
{
    QString dlgTitle="Choose Save Directory";   //title
    QString savedir = QFileDialog::getExistingDirectory(this,dlgTitle,curPath,QFileDialog::ShowDirsOnly
                                                     | QFileDialog::DontResolveSymlinks);
    if(savedir.length() != 0){
        QString tempfilename = curPath+"/temp/flow.txt";
        QString savefilename = savedir+settings->value("DataSave/FLOWFILENAME").toString();
        obj_datafile_path.flowpath = savefilename;
        QFile savefile(savefilename);
        if(savefile.exists()){  //若之前已经存在此文件，则先删除此文件
            savefile.remove();
        }
        QFile tempfile(tempfilename);
        if(tempfile.copy(savefilename)){
            show_tips("成功保存流量数据至"+savedir+settings->value("DataSave/FLOWFILENAME").toString());
            print_log("成功保存流量数据至"+savedir+settings->value("DataSave/FLOWFILENAME").toString(), 0);
        }
    }
}

/**
 * @brief 调用本机记事本程序打开历史温度数据
 */
void Serial::query_temperData_history()
{
    QStringList cmd;
    cmd << QDir::toNativeSeparators(curPath+"/temp/temper.txt");
    QProcess::startDetached("notepad", cmd);

    print_log("查看历史温度数据", 0);
    show_tips("查看历史温度数据");
}

/**
 * @brief 调用本机记事本程序打开历史流量数据
 */
void Serial::query_flowData_history()
{
    QStringList cmd;
    cmd << QDir::toNativeSeparators(curPath+"/temp/flow.txt");
    QProcess::startDetached("notepad", cmd);

    print_log("查看历史流量数据", 0);
    show_tips("查看历史流量数据");
}


/**
 * @brief 设置温度安全上限
 */
void Serial::set_temper_upper()
{
error:
    bool bOk = false;
    QInputDialog inputd;
    QString tempstr = inputd.getText(this,
                                       "温度参数设置",
                                       "请输入温度安全上限参数<font color='red'>(℃)</font>",
                                       QLineEdit::Normal,
                                       "",
                                       &bOk
                                       );

    inputd.setGeometry(this->frameGeometry().x()+this->frameGeometry().width()/2-178/2,
                       this->frameGeometry().y()+this->frameGeometry().height()/2-116/2, inputd.width(), inputd.height());

    if(bOk){    //点击OK
        int length = sizeof(tempstr.toStdString());
        char* tempchar = new char[length];
        strcpy(tempchar,tempstr.toStdString().c_str());
        if(isFloat(tempchar) || isInt(tempchar)){
            settings->setValue("SaveScope/TEMPER_UPPER", tempstr);
            QMessageBox::about(NULL, "提示", "<font color='red'>修改成功!</font>");

            obj_safe_scope.temper_upper = tempstr.toFloat(); //更新温度安全上限

            if(unit_temper_ssd){
                ui->le_Upper_temper->setText(tempstr);
            }else{
                ui->le_Upper_temper->setText(QString("%1").arg(32+obj_safe_scope.temper_upper*1.8));
            }


            obj_resetFlag.reset_temper = false;   //温度复位标志失效
            show_tips("温度安全上限已经重新设置为"+tempstr+"℃");
            print_log("温度上限设置为"+tempstr+"℃",0);
        }else{
            QMessageBox::about(NULL, "提示", "<font color='red'>参数输入错误,请重新输入！</font>");
            goto error;
        }
     }
}

/**
 * @brief 设置温度安全下限
 */
void Serial::set_temper_lower()
{
error:
    bool bOk = false;
    QString tempstr = QInputDialog::getText(this,
                                         "温度参数设置",
                                         "请输入温度安全下限参数<font color='red'>(℃)</font>",
                                         QLineEdit::Normal,
                                         "",
                                         &bOk
                                         );
    if(bOk){    //点击OK
        int length = sizeof(tempstr.toStdString());
        char* tempchar = new char[length];
        strcpy(tempchar,tempstr.toStdString().c_str());
        if(isFloat(tempchar) || isInt(tempchar)){
            settings->setValue("SaveScope/TEMPER_LOWER", tempstr);
            QMessageBox::about(NULL, "提示", "<font color='red'>修改成功!</font>");

            obj_safe_scope.temper_lower = tempstr.toFloat(); //更新温度安全下限

            if(unit_temper_ssd){
                ui->le_Lower_temper->setText(tempstr);
            }else{
                ui->le_Lower_temper->setText(QString("%1").arg(32+obj_safe_scope.temper_lower*1.8));
            }



            obj_resetFlag.reset_temper = false;   //温度复位标志失效

            show_tips("温度安全下限已经重新设置为"+tempstr+"℃");
            print_log("温度下限设置为"+tempstr+"℃",0);

        }else{
            QMessageBox::about(NULL, "提示", "<font color='red'>参数输入错误,请重新输入！</font>");
            goto error;
        }
     }
}

/**
 * @brief 设置流量安全上限
 */
void Serial::set_flow_upper()
{
error:
    bool bOk = false;
    QString tempstr = QInputDialog::getText(this,
                                         "温度参数设置",
                                         "请输入流量安全上限参数<font color='red'>(ml/min)</font>",
                                         QLineEdit::Normal,
                                         "",
                                         &bOk
                                         );
    if(bOk){    //点击OK
        int length = sizeof(tempstr.toStdString());
        char* tempchar = new char[length];
        strcpy(tempchar,tempstr.toStdString().c_str());
        if(isFloat(tempchar) || isInt(tempchar)){
            settings->setValue("SaveScope/FLOW_UPPER", tempstr);
            QMessageBox::about(NULL, "提示", "<font color='red'>修改成功!</font>");

            obj_safe_scope.flow_upper = tempstr.toFloat();  //更新流量安全上限

            if(unit_temper_ssd){
                ui->le_Upper_flow->setText(tempstr);
            }else{
                ui->le_Upper_flow->setText(QString("%1").arg(obj_safe_scope.flow_upper*0.06));
            }


            obj_resetFlag.reset_flow = false;   //流量复位标志失效

            show_tips("流量安全上限已经重新设置为"+tempstr+"ml/min");
            print_log("流量上限设置为"+tempstr+"ml/min",0);
        }else{
            QMessageBox::about(NULL, "提示", "<font color='red'>参数输入错误,请重新输入！</font>");
            goto error;
        }
     }
}

/**
 * @brief 设置流量安全下限  大于0
 */
void Serial::set_flow_lower()
{
error:
    bool bOk = false;
    QString tempstr = QInputDialog::getText(this,
                                         "温度参数设置",
                                         "请输入流量安全下限参数<font color='red'>(ml/min)</font>",
                                         QLineEdit::Normal,
                                         "",
                                         &bOk
                                         );
    if(bOk){    //点击OK
        int length = sizeof(tempstr.toStdString());
        char* tempchar = new char[length];
        strcpy(tempchar,tempstr.toStdString().c_str());
        if(isFloat(tempchar) || isInt(tempchar)){
            settings->setValue("SaveScope/FLOW_LOWER", tempstr);
            QMessageBox::about(NULL, "提示", "<font color='red'>修改成功!</font>");

            obj_safe_scope.flow_lower = tempstr.toFloat();  //更新流量安全下限

            if(unit_temper_ssd){
                ui->le_Lower_flow->setText(tempstr);
            }else{
                ui->le_Lower_flow->setText(QString("%1").arg(obj_safe_scope.flow_lower*0.06));
            }

            obj_resetFlag.reset_flow = false;   //流量复位标志失效

            show_tips("流量安全下限已经重新设置为"+tempstr+"ml/min");
            print_log("流量下限设置为"+tempstr+"ml/min",0);
        }else{
            QMessageBox::about(NULL, "提示", "<font color='red'>参数输入错误,请重新输入！</font>");
            goto error;
        }
     }
}

/**
 * @brief 分割温度和流量
 * @param str
 */
void Serial::ArraySplit(QByteArray str)
{
    QDataStream out(&str,QIODevice::ReadWrite);
    QString buf;
    char buf_t[20], buf_f[20];
    bool ok;
    while(!out.atEnd())
    {
       qint8 outChar = 0;
       out >> outChar;   //每次一个字节的填充到 outchar
       QString str = QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0')).toUpper();   //2 字符宽度
       buf += str;
    }
    sprintf(buf_t, "%d.%2d", buf.mid(10,4).toInt(&ok, 16)/100, buf.mid(10,4).toInt(&ok, 16)%100);//分割数据
    sprintf(buf_f, "%d.%2d", buf.mid(6,4).toInt(&ok, 16)/100, buf.mid(6,4).toInt(&ok, 16)%100);
    obj_param.temper_f = QString(QLatin1String(buf_t)).toFloat()==0?obj_param.temper_f:QString(QLatin1String(buf_t)).toFloat();
    obj_param.flow_f = QString(QLatin1String(buf_f)).toFloat();
}


/**
 * @brief 加载.ini配置文件，可打开可运行目录下的XXX.ini文件以便加深理解
 */
void Serial::loadConfigData()
{
    configData.port_name = settings->value("Serial/PORT_NAME",defaultConfigData.port_name).toString();   //端口号配置
    configData.baud_rate = settings->value("Serial/BAUD_RATE",defaultConfigData.baud_rate).toInt();      //波特率配置
    configData.check_bit = settings->value("Serial/CHECK_BIT",defaultConfigData.check_bit).toString();   //校验位配置
    configData.data_bit = settings->value("Serial/DATA_BIT",defaultConfigData.data_bit).toInt();         //数据位配置
    configData.stop_bit = settings->value("Serial/STOP_BIT",defaultConfigData.stop_bit).toInt();         //停止位配置


    /*----------获取“接口型号”节点下的所有参数----------*/
    settings->beginGroup("InterfaceM");             //设置查找的节点
    QStringList interface_key = settings->allKeys();//获取所有key
    int interface_index = 0;
    foreach(QString key, interface_key){
        QString interface_value = settings->value(key).toString();   //获取每个键下的value
        ui->cmbInterface->insertItem(interface_index, interface_value); //顺序插入到“接口型号”中
        interface_index += 1;
    }
    settings->endGroup();    //结束查找的节点
    /*---------------------END-------------------------*/

    /*----------获取“产品类别”节点下的所有参数----------*/
    settings->beginGroup("ProductCate");              //设置查找的节点
    QStringList product_key = settings->allKeys();    //获取所有key
    int product_index = 0;
    foreach(QString key, product_key){
        QString interface_value = settings->value(key).toString();   //获取每个键下的value
        ui->cmbProductCategory->insertItem(product_index, interface_value); //顺序插入到“产品类别”中
        product_index += 1;
    }
    settings->endGroup();    //结束查找的节点
    /*---------------------END-------------------------*/

    /*-----------------获取“系统信息”参数-----------------*/
    QString sysinfo = settings->value("SysInfo/INFO").toString();
    ui->plain_SysInfo->insertPlainText(sysinfo);
    ui->plain_SysInfo->setReadOnly(true);
    /*---------------------END-------------------------*/

    /*-----------------LCD显示启动参数-----------------*/
    set_warning_LED(48, green);    //设置显示报警灯大小
    QString temper_upper = settings->value("SaveScope/TEMPER_UPPER").toString();
    QString temper_lower = settings->value("SaveScope/TEMPER_LOWER").toString();
    QString flow_upper = settings->value("SaveScope/FLOW_UPPER").toString();
    QString flow_lower = settings->value("SaveScope/FLOW_LOWER").toString();

    obj_safe_scope.temper_upper = temper_upper.toFloat();   //温度上限赋值
    obj_safe_scope.temper_lower = temper_lower.toFloat();   //温度下限赋值
    obj_safe_scope.flow_upper = flow_upper.toFloat();       //流量上限赋值
    obj_safe_scope.flow_lower = flow_lower.toFloat();       //流量下限赋值

    ui->le_Upper_temper->setText(temper_upper);
    ui->le_Upper_temper->setAlignment(Qt::AlignHCenter);    //文字中间显示
    ui->le_Lower_temper->setText(temper_lower);
    ui->le_Lower_temper->setAlignment(Qt::AlignHCenter);
    ui->le_Upper_flow->setText(flow_upper);
    ui->le_Upper_flow->setAlignment(Qt::AlignHCenter);
    ui->le_Lower_flow->setText(flow_lower);
    ui->le_Lower_flow->setAlignment(Qt::AlignHCenter);
    ui->lb_lcd_temper_name->setAlignment(Qt::AlignCenter);
    ui->lb_lcd_flow_name->setAlignment(Qt::AlignCenter);
    /*---------------------END-------------------------*/

    showUIConfigData();//将配置信息显示在UI页面中
}


/**
 * @brief 设置LED报警灯的样式
 * @param size
 * @param color
 */
void Serial::set_warning_LED(int size, int color)
{
    ui->lb_TemperStatus->setText("");   //清空
    ui->lb_FlowStatus->setText("");     //清空
    QString min_width = QString("min-width: %1px;").arg(size);              // 最小宽度：size
    QString min_height = QString("min-height: %1px;").arg(size);            // 最小高度：size
    QString max_width = QString("max-width: %1px;").arg(size);              // 最小宽度：size
    QString max_height = QString("max-height: %1px;").arg(size);            // 最小高度：size
    // 再设置边界形状及边框
    QString border_radius = QString("border-radius: %1px;").arg(size/2);    // 边框是圆角，半径为size/2
    QString border = QString("border:1px solid black;");                    // 边框为1px黑色
    // 最后设置背景颜色
    QString background;
    if(color == green){
        background = "background-color:rgb(0,255,0)";   //默认绿色
    }else{
        background = "background-color:red";   //默认绿色
    }
    const QString SheetStyle = min_width + min_height + max_width + max_height + border_radius + border + background;
    ui->lb_TemperStatus->setStyleSheet(SheetStyle);
    ui->lb_FlowStatus->setStyleSheet(SheetStyle);
}

/**
 * @brief 主动获取计算机所有串口信息，并读取ini文件设置默认显示的串口号
 */
void Serial::getSerialPort()
{
    bool tips_flag = true;
    QString port_name1 = settings->value("Serial/PORT_NAME",defaultConfigData.port_name).toString();   //端口号配置

    ui->cmbSerialPort->clear();      //清空现有的串口号选项
    for (auto portInfo: QSerialPortInfo::availablePorts()){ //获取本机所有串口名称
        ui->cmbSerialPort->addItem(portInfo.portName());    //将串口名添加到组合框中
    }

    for(int i = 0; i < ui->cmbSerialPort->count(); i++){    //遍历端口号
        if(port_name1 == ui->cmbSerialPort->itemText(i)){
            ui->cmbSerialPort->setCurrentIndex(i);//将与配置文件匹配的选项设为当前默认项
        }else{//连接的串口不在扫描的串口中，无操作
        }
    }

    if(serial_conn_flag){
        for(int i = 0; i < ui->cmbSerialPort->count(); i++){
            if(global_port.portName() == ui->cmbSerialPort->itemText(i)){
                //连接的串口在扫描的串口中，无需操作
                tips_flag = false;  //连接的 设备串口号存在于连接在PC机中的串口列表中，则正常运行
            }
        }
        if(tips_flag){
            //连接的串口不在扫描的串口中，进行提示，同时关闭串口
            QMessageBox *msgbox = new QMessageBox;
            msgboxcreate(msgbox, "提示", "<font color='red'>串口连接中断！</font>", 2);
            int ret = msgbox->exec();
            if(ret == QMessageBox::Ok){
                btn_CloseSerial_clicked();  //连接中断时自动点击关闭串口
                serial_conn_flag = false;   //复位串口连接状态标志位为断开

                obj_param.flow_f = 0;
                obj_param.temper_f = 0;          //实时数据归零
                ui->lcd_FlowValue->display(0);
                ui->lcd_TemperValue->display(0); //lcd显示数据清零
                btn_reset_allParam_alarm();      //复位所有报警
                return ;
            }
        }
    }
}

/**
 * @brief 配置波特率，默认读取ini配置文件
 */
void Serial::ConfigBuadRate()
{
    ui->cmbBaudRate->clear();                               //清空现有的串口号选项
    ui->cmbBaudRate->insertItem(0,QString::number(configData.baud_rate));    //在串口号组合框中，插入第一个默认的项
    ui->cmbBaudRate->setCurrentIndex(0);                    //将第0项设为当前默认项
    ui->cmbBaudRate->addItem("115200");
    ui->cmbBaudRate->addItem("38400");
    ui->cmbBaudRate->addItem("19200");
    ui->cmbBaudRate->addItem("9600");
    ui->cmbBaudRate->addItem("4800");
    ui->cmbBaudRate->addItem("2400");
    ui->cmbBaudRate->addItem("1200");
}

/**
 * @brief 配置校验位，默认读取ini配置文件
 */
void Serial::ConfigCheckBit()
{
    ui->cmbCheckBit->clear();
    ui->cmbCheckBit->insertItem(0, configData.check_bit);
    ui->cmbCheckBit->setCurrentIndex(0);
    ui->cmbCheckBit->addItem("Odd");
    ui->cmbCheckBit->addItem("Even");
}

/**
 * @brief 配置数据位，默认读取ini配置文件
 */
void Serial::ConfigDataBit()
{
    ui->cmbDataBit->clear();
    ui->cmbDataBit->insertItem(0, QString::number(configData.data_bit));
    ui->cmbDataBit->setCurrentIndex(0);
    ui->cmbDataBit->addItem("8");
    ui->cmbDataBit->addItem("7");
    ui->cmbDataBit->addItem("6");
    ui->cmbDataBit->addItem("5");
}

/**
 * @brief 配置停止位，默认读取ini配置文件
 */
void Serial::ConfigStopRate()
{
    ui->cmbStopBit->clear();
    ui->cmbStopBit->insertItem(0, QString::number(configData.stop_bit));
    ui->cmbStopBit->setCurrentIndex(0);
    ui->cmbStopBit->addItem("1");
    ui->cmbStopBit->addItem("2");
}

/**
 * @brief 查找本机支持的串口端口号并根据配置文件，重新显示UI界面
 * @param configData
 */
void Serial::showUIConfigData()
{
    getSerialPort();    //串口信息列表
    ConfigBuadRate();   //波特率信息列表
    ConfigCheckBit();   //校验位信息列表
    ConfigDataBit();    //数据位列表
    ConfigStopRate();   //停止位列表
}

/**
 * @brief 按照用户选择或者默认ini配置打开串口
 */
void Serial::btn_OpenSerial_clicked()
{
    global_port.setPortName(ui->cmbSerialPort->currentText());
    global_port.setBaudRate((ui->cmbBaudRate->currentText()).toInt());

    //compare中 Qt::CaseInsensitive代表大小写不敏感，Qt::CaseSensitive表示大小写敏感
    if(QString::compare(ui->cmbCheckBit->currentText(), "None", Qt::CaseInsensitive) == 0){
        global_port.setParity(QSerialPort::NoParity);
    }else if(QString::compare(ui->cmbCheckBit->currentText(), "Odd", Qt::CaseInsensitive) == 0){
        global_port.setParity(QSerialPort::OddParity);
    }else if(QString::compare(ui->cmbCheckBit->currentText(), "Even", Qt::CaseInsensitive) == 0){
        global_port.setParity(QSerialPort::EvenParity);
    }

    if((ui->cmbDataBit->currentText()).toInt() == 8){
        global_port.setDataBits(QSerialPort::Data8);
    }else if((ui->cmbDataBit->currentText()).toInt() == 7){
        global_port.setDataBits(QSerialPort::Data7);
    }else if((ui->cmbDataBit->currentText()).toInt() == 6){
        global_port.setDataBits(QSerialPort::Data6);
    }else if((ui->cmbDataBit->currentText()).toInt() == 5){
        global_port.setDataBits(QSerialPort::Data5);
    }

    if((ui->cmbStopBit->currentText()).toInt() == 1){
        global_port.setStopBits(QSerialPort::OneStop);
    }else if((ui->cmbDataBit->currentText()).toInt() == 2){
        global_port.setStopBits(QSerialPort::TwoStop);
    }

    port_flag = global_port.open(QSerialPort::ReadWrite);
    if(port_flag){
        show_tips(global_port.portName()+"打开串口成功!");
        print_log("打开串口"+global_port.portName(),0);

        send_cmd_timer.start(1000);     //自动发送命令定时器启动
        ui->btn_OpenSerial->setDisabled(1);         //设置打开串口不可点击
        ui->btn_CloseSerial->setEnabled(1);         //设置关闭串口可点击

        ui->btn_temper_save_data->setEnabled(1);    //设置温度保存按钮可点击
        ui->btn_flow_save_data->setEnabled(1);      //设置流量保存按钮可点击
        ui->btn_temper_history_data->setEnabled(1); //设置历史数据查看可点击
        ui->btn_flow_history_data->setEnabled(1);   //设置历史数据查看可点击

        ui->btn_setSlaveAddr->setEnabled(1);        //设置新地址可点击
        ui->btn_setSerial_param->setEnabled(1);     //设置modbus串口参数按钮可点击
        ui->btn_Serial_back->setEnabled(1);         //modbus串口参数还原按钮可点击

        serial_conn_flag = true;    //串口连接状态为true

        //串口打开之后按照本次连接设置自动保存配置
        settings->setValue("Serial/PORT_NAME", ui->cmbSerialPort->currentText());
        settings->setValue("Serial/BAUD_RATE", ui->cmbBaudRate->currentText().toInt());
        settings->setValue("Serial/DATA_BIT", ui->cmbDataBit->currentText().toInt());
        settings->setValue("Serial/CHECK_BIT", ui->cmbCheckBit->currentText());
        settings->setValue("Serial/STOP_BIT", ui->cmbStopBit->currentText().toInt());
    }else{
        show_tips(global_port.portName()+"打开串口失败!");
        print_log("串口"+global_port.portName()+"打开失败",0);
        return;
    }

}


/**
 * @brief QT窗口左下角显示提示信息
 * @param tip，传入的提示语
 */
void Serial::show_tips(QString tip)
{
    this->lb_tips->clear();
    this->lb_tips->setText(tip);
    ui->statusBar->addWidget(this->lb_tips);
}

/**
 * @brief 关闭串口
 */
void Serial::btn_CloseSerial_clicked()
{
    global_port.close();
    send_cmd_timer.stop();  //关闭自动发送命令定时器
    qDebug()<<"serial port close succ!";
    port_flag = false;
    ui->btn_OpenSerial->setEnabled(1);
    ui->btn_CloseSerial->setDisabled(1);


    ui->btn_temper_save_data->setDisabled(1);
    ui->btn_flow_save_data->setDisabled(1);

    ui->btn_setSlaveAddr->setDisabled(1);        //设置新地址不可点击
    ui->btn_setSerial_param->setDisabled(1);     //设置modbus串口参数按钮不可点击
    ui->btn_Serial_back->setDisabled(1);         //modbus串口参数还原按钮不可点击

    show_tips(global_port.portName()+"串口成功关闭!");
    print_log("关闭串口"+global_port.portName(),0);
}






/**
 * @brief 自动报警
 */
void Serial::auto_alarm_check()
{
    /*--------------------------温度报警检测(Begin)--------------------------*/
    if(obj_resetFlag.reset_temper == true){ //如果温度报警复位键按下
        obj_alarmType.alarm_temper = false;
        obj_alarmType.alarm_temper_lower = false;
        obj_alarmType.alarm_temper_upper = false;

        ui->le_Upper_temper->setStyleSheet("color:blue");
        ui->le_Lower_temper->setStyleSheet("color:blue");
        ui->lb_TemperStatus->setStyleSheet(green_SheetStyle);
    }else{  //重新调整了温度上下限或者从未按过复位键，报警标志位失效
        if(obj_param.temper_f >= obj_safe_scope.temper_upper ||
           obj_param.temper_f < obj_safe_scope.temper_lower){
            obj_alarmType.alarm_temper = true;
            auto_alarm_Temp_LED();
            if(obj_param.temper_f >= obj_safe_scope.temper_upper){ //超过温度上限
                obj_alarmType.alarm_temper_upper = true;
                obj_alarmType.alarm_temper_lower = false;
                ui->le_Upper_temper->setStyleSheet("color:red");
                print_log("当前温度"+QString("%1℃").arg(obj_param.temper_f)+"超过上限值"+ui->le_Upper_temper->text()+"℃",1);
            }else{
                obj_alarmType.alarm_temper_upper = false;
                ui->le_Lower_temper->setStyleSheet("color:blue");
            }
            if(obj_param.temper_f < obj_safe_scope.temper_lower){ //低于温度下限
                obj_alarmType.alarm_temper_lower = true;
                obj_alarmType.alarm_temper_upper = false;
                ui->le_Lower_temper->setStyleSheet("color:red");
//                char str[10];
//                sprintf(str, "%f℃",ui->lcd_TemperValue);
//                print_log("当前温度"+QString(str)+"低于下限值"+ui->le_Lower_temper->text());
                print_log("当前温度"+QString("%1℃").arg(obj_param.temper_f)+"低于下限值"+ui->le_Lower_temper->text()+"℃",1);
            }else{
                obj_alarmType.alarm_temper_lower = false;
                ui->le_Lower_temper->setStyleSheet("color:blue");
            }
        }else{  //复位
            obj_alarmType.alarm_temper = false;
            obj_alarmType.alarm_temper_lower = false;
            obj_alarmType.alarm_temper_upper = false;

            ui->le_Upper_temper->setStyleSheet("color:blue");
            ui->le_Lower_temper->setStyleSheet("color:blue");
            ui->lb_TemperStatus->setStyleSheet(green_SheetStyle);
        }
    }
    /*--------------------------温度报警检测(End)--------------------------*/

    /*--------------------------流量报警检测(Begin)--------------------------*/
    if(obj_resetFlag.reset_flow == true){ //如果流量报警复位键按下
        obj_alarmType.alarm_flow = false;
        obj_alarmType.alarm_flow_lower = false;
        obj_alarmType.alarm_flow_upper = false;

        ui->le_Upper_flow->setStyleSheet("color:blue");
        ui->le_Lower_flow->setStyleSheet("color:blue");
        ui->lb_FlowStatus->setStyleSheet(green_SheetStyle);
    }else{  //重新调整了流量上下限或者从未按过复位键，报警标志位失效
        if(obj_param.flow_f >= obj_safe_scope.flow_upper ||
           obj_param.flow_f < obj_safe_scope.flow_lower){
            obj_alarmType.alarm_flow = true;
            auto_alarm_Flow_LED();
            if(obj_param.flow_f >= obj_safe_scope.flow_upper){ //超过流量上限
                obj_alarmType.alarm_flow_upper = true;
                obj_alarmType.alarm_flow_lower = false;
                ui->le_Upper_flow->setStyleSheet("color:red");
                print_log("当前流量"+QString("%1ml/min").arg(obj_param.flow_f)+"超过上限值"+ui->le_Upper_flow->text()+"ml/min",1);
            }else{
                obj_alarmType.alarm_flow_upper = false;
                ui->le_Upper_flow->setStyleSheet("color:blue");
            }

            if(obj_param.flow_f < obj_safe_scope.flow_lower){ //低于流量下限
                obj_alarmType.alarm_flow_lower = true;
                obj_alarmType.alarm_flow_upper = false;
                ui->le_Lower_flow->setStyleSheet("color:red");

                print_log("当前流量"+QString("%1ml/min").arg(obj_param.flow_f)+"超过下限值"+ui->le_Lower_flow->text()+"ml/min",1);
            }else{
                obj_alarmType.alarm_flow_lower = false;
                ui->le_Lower_flow->setStyleSheet("color:blue");
            }
        }else{  //复位
            obj_alarmType.alarm_flow = false;
            obj_alarmType.alarm_flow_lower = false;
            obj_alarmType.alarm_flow_upper = false;

            ui->le_Upper_flow->setStyleSheet("color:blue");
            ui->le_Lower_flow->setStyleSheet("color:blue");
            ui->lb_FlowStatus->setStyleSheet(green_SheetStyle);
        }
    }
    /*--------------------------流量报警检测(End)--------------------------*/
}

/**
 * @brief 报警灯闪烁
 * @param ptype
 * @param ctype
 */
void Serial::auto_alarm_Temp_LED()
{
    alarm_toggle = !alarm_toggle;
    if(obj_alarmType.alarm_temper){   //温度报警
        if(alarm_toggle == false){
            ui->lb_TemperStatus->setStyleSheet(red_SheetStyle);
        }else{
            ui->lb_TemperStatus->setStyleSheet(green_SheetStyle);
        }
    }
}


/**
 * @brief 流量报警灯闪烁
 * @param ptype
 * @param ctype
 */
void Serial::auto_alarm_Flow_LED()
{
    alarm_toggle2 = !alarm_toggle2;

    if(obj_alarmType.alarm_flow){   //流量温度报警
        if(alarm_toggle2 == false){
            ui->lb_FlowStatus->setStyleSheet(red_SheetStyle);
        }else{
            ui->lb_FlowStatus->setStyleSheet(green_SheetStyle);
        }
    }
}

/*--------------------------报警复位标志位槽函数Begin------------------------*/
void Serial::btn_reset_temper_alarm(){obj_resetFlag.reset_temper = true; show_tips("温度报警已复位!");print_log("复位温度报警",0);}
void Serial::btn_reset_flow_alarm(){obj_resetFlag.reset_flow = true;show_tips("流量报警已复位!");print_log("复位流量报警",0);}
void Serial::btn_reset_allParam_alarm(){obj_resetFlag.reset_temper = true;obj_resetFlag.reset_flow = true;show_tips("所有报警均已复位!");print_log("复位所有报警",0);}
/*--------------------------报警复位标志位槽函数End--------------------------*/


/**
 * @brief 打印操作日志
 * @param str, type   type==1时为紧急通知，显示红色   type==0时正常显示
 */
void Serial::print_log(QString str, int type)
{
    QTextCursor textCursor = ui->te_logShow->textCursor();
    textCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);//滚动条显示到最下方
    ui->te_logShow->setTextCursor(textCursor);

    if(type == 1){
        ui->te_logShow->setTextColor(Qt::red);  // 设置当前行要使用的颜色
        ui->te_logShow->append(ui->lb_datetime->text()+"  "+str);
    }else{
        ui->te_logShow->setTextColor(Qt::blue);
        ui->te_logShow->append(ui->lb_datetime->text()+"  "+str);
    }
}

/**
 * @brief 清除日志
 */
void Serial::btn_clear_log(){this->ui->te_logShow->clear();}

/**
 * @brief 保存当前日志
 */
void Serial::btn_save_log()
{
    if(ui->te_logShow->toPlainText().length() == 0){
        QMessageBox::about(NULL, "提示", "<font color='blue'>日志为空，无需保存！</font>");
        return;
    }

    QString dlgTitle="Choose Save Directory";   //title
    QString savedir = QFileDialog::getExistingDirectory(this,dlgTitle,curPath,QFileDialog::ShowDirsOnly
                                                     | QFileDialog::DontResolveSymlinks);
    if(savedir.length() != 0){  //判断选择的文件路径是否为空（打开选择框但是点击了取消）
        QFile logfile(savedir+"/log.txt");
        if(logfile.exists()){  //存在此文件先删除
            logfile.remove();
        }
        logfile.open(QIODevice::ReadWrite | QIODevice::Append);  //以读写切追加写入的方式操作文本
        QTextStream dataWrite(&logfile);
        dataWrite<<ui->te_logShow->toPlainText()<<endl;
        logfile.close();

        show_tips("日志文件成功保存至"+savedir+"/log.txt");
        print_log("成功保存日志至"+savedir+"/log.txt",0);
    }
}

/**
 * @brief 设置从机地址，弹框修改
 *        功能码：06 写地址
 *        数据帧格式：原地址  06  00 02 新地址(1-255,占四位)  校验码高位  校验码低位
 */
void Serial::btn_set_slave_addr()
{
    bool bOk = false;
error:
    QString slave_addr = QInputDialog::getText(this,
                                             "从机地址设置",
                                             "请输入新的从机地址",
                                             QLineEdit::Normal,
                                             "",
                                             &bOk
                                             );
    if(bOk){
        obj_send_crcCal_tf.new_addr_data[0] = "00";
        if(slave_addr == obj_send_crcCal_tf.old_addr){
            //修改地址与原地址相同
            //做相应处理
            QMessageBox::about(NULL, "提示", "<font color='red'>请输入与原地址"+obj_send_crcCal_tf.old_addr+"不同的地址!</font>");
            goto error;
            //return;
        }
        obj_send_crcCal_tf.new_addr_data[1] = slave_addr;

       //obj_send_crcCal_tf.addr = "01";     //地址码
        obj_send_crcCal_tf.func_write_addr = "06";       //功能码，写
        obj_send_crcCal_tf.new_addr_reg[0] = "00";
        obj_send_crcCal_tf.new_addr_reg[1] = "02";       //从机寄存器地址

        QString str = obj_send_crcCal_tf.old_addr+obj_send_crcCal_tf.func_write_addr+obj_send_crcCal_tf.new_addr_reg[0]+obj_send_crcCal_tf.new_addr_reg[1]+obj_send_crcCal_tf.new_addr_data[0]+obj_send_crcCal_tf.new_addr_data[1];
        QString crc = crcCalculation(str);
        QString cmd = str+crc;
        qDebug()<<"cmd:"<<cmd;

        if(-1 == global_port.write(QString2Hex(cmd.toLatin1()))){ //写命令修改地址
            //写地址出错
            //做相应处理
            QMessageBox::about(NULL, "提示", "<font color='red'>从机地址修改出错!</font>");
            return;
        }
        global_port.flush();
        obj_send_crcCal_tf.old_addr = obj_send_crcCal_tf.new_addr_data[1];

        QString read_data_str = obj_send_crcCal_tf.old_addr+obj_send_crcCal_tf.func_read_data+obj_send_crcCal_tf.start_addr[0]+obj_send_crcCal_tf.start_addr[1]+obj_send_crcCal_tf.data_len[0]+obj_send_crcCal_tf.data_len[1];
        obj_send_crcCal_tf.crc = crcCalculation(read_data_str);
        qDebug()<<"after:"<<read_data_str+obj_send_crcCal_tf.crc;
        ui->le_slave_addr->setText(obj_send_crcCal_tf.new_addr_data[1]);    //显示新的从机地址
        settings->setValue("SlaveAddr/SLAVEADDR", obj_send_crcCal_tf.new_addr_data[1]);
        QMessageBox::about(NULL, "提示", "<font color='blue'>从机地址成功修改为"+obj_send_crcCal_tf.new_addr_data[1]+"</font>");

        print_log("从机地址成功修改为"+ obj_send_crcCal_tf.new_addr_data[1], 0);
        show_tips("从机地址修改成功！");
    }
}

/**
 * @brief 设置modbus串口连接参数
 *        参数全部取自下拉框
 *        1.模块地址：
 *        2.功  能 码：06
 *        3.寄存器地址：
 *        4.数     据：
 *        ---------------------------------------------------------------
 *        15-12位波特率   11-8位--数据位   7-4位--停止位   0-3位--奇偶校验位
 *          0--4800         0--8            0--1            0--None
 *          1--9600         1--9            1--1.5          1--Odd
 *          2--19200        2--无            2--2           2--Even
 *          3--38400        3--无            3--无           3--无
 *          4--43000        4--无            4--无           4--无
 *          5--56000        5--无            5--无           5--无
 *          6--57600        6--无            6--无           6--无
 *          7--115200       7--无            7--无           7--无
 *        ---------------------------------------------------------------
 *        5.CRC校验位：
 *        例子：修改01从机通信参数为波特率9600,8位数据位，1位停止位，无奇偶校验位的数据帧为01 06 00 03 10 00 74 0A（16 进制）
 */
void Serial::btn_set_serial_param()
{
    QString baud_rate = ui->cmb_baudRate_set->currentText();
    QString check_bit = ui->cmb_checkBit_set->currentText();
    QString dataBit_rate = ui->cmb_dataBit_set->currentText();
    QString stop_bit = ui->cmb_stopBit_set->currentText();
}

/**
 * @brief 还原modbus串口连接参数
 *        波特率--9600
 *        数据位--8
 *        停止位--1
 *        奇偶校验位--None
 */
void Serial::btn_back_serial_param()
{
    QMessageBox *msgbox = new QMessageBox;
    msgboxcreate(msgbox, "提示","确定要还原串口连接参数吗？", 1);
    int ret = msgbox->exec();
    if(ret == QMessageBox::Ok){
        //还原参数
    }
}

/**
 * @brief 还原实时监控数据的安全上下限参数
 *        温度上限：50℃
 *        温度下限：-10℃
 *        流量上限：30   待修改
 *        流量下限：0
 */
void Serial::btn_back_safe_limit_param()
{
    QMessageBox *msgbox = new QMessageBox;
    msgboxcreate(msgbox, "提示","确定要还原参数吗？", 1);
    int ret = msgbox->exec();
    if(ret == QMessageBox::Ok){
        //还原操作
        settings->setValue("SaveScope/TEMPER_UPPER", 50);
        settings->setValue("SaveScope/TEMPER_LOWER", -10);
        settings->setValue("SaveScope/FLOW_UPPER", 30);
        settings->setValue("SaveScope/FLOW_LOWER", 0);
        ui->le_Upper_temper->setText("50");
        ui->le_Lower_temper->setText("-10");
        ui->le_Upper_flow->setText("30");
        ui->le_Lower_flow->setText("0");
        obj_resetFlag.reset_temper = false;   //温度复位标志失效
        obj_resetFlag.reset_flow = false;     //流量复位标志失效
        QMessageBox::about(NULL, "提示", "<font color='blue'>参数还原完成！</font>");
        show_tips("参数安全上下限还原成功！");
        print_log("参数安全上下限还原完毕", 0);
    }
}

/*---------------------------菜单栏设计函数(Begin)-------------------------------------*/
/**
 * @brief 菜单栏退出
 */
void Serial::menu_exit_click()
{
    QMessageBox *msgbox = new QMessageBox;
    msgboxcreate(msgbox, "提示","确定要退出吗？", 1);

    int ret = msgbox->exec();
    if(ret == QMessageBox::Ok){
        this->close();
    }
}

/**
 * @brief 菜单栏打开日志文件
 */
void Serial::menu_open_log_file()
{
    if(!path->exists("log")){
        //不存在此目录
        QMessageBox *msgbox = new QMessageBox;
        msgboxcreate(msgbox, "提示", "日志文件夹不存在", 2);
        msgbox->exec();

        return ;
    }

    QFile tempfile1(curPath+"/log/log.txt");
    if(!tempfile1.exists()){
        //不存在文件
        QMessageBox *msgbox = new QMessageBox;
        msgboxcreate(msgbox, "提示", "日志文件不存在", 2);
        msgbox->exec();
        return;
    }

    QStringList cmd;
    cmd << QDir::toNativeSeparators(tempfile1.fileName());
    QProcess::startDetached("notepad", cmd);

    print_log("日志文件已打开", 0);
    show_tips("日志文件已打开");
}

/**
 * @brief 菜单栏打开日志文件夹
 */
void Serial::menu_open_log_fold()
{
    if(!path->exists("log")){
        //不存在此目录
        QMessageBox *msgbox = new QMessageBox;
        msgboxcreate(msgbox, "提示", "日志文件夹不存在", 2);
        msgbox->exec();

        return ;
    }

    bool ok = QDesktopServices::openUrl(QUrl::fromLocalFile(curPath+"/log/"));
    if(ok){
        print_log("日志文件夹已打开", 0);
        show_tips("日志文件夹已打开");
    }else{
    }
}

/**
 * @brief 打开临时文件夹
 */
void Serial::menu_open_temp_fold()
{
    if(!path->exists("temp")){
        //不存在此目录
        QMessageBox *msgbox = new QMessageBox;
        msgboxcreate(msgbox, "提示", "临时文件夹不存在", 2);
        msgbox->exec();

        return ;
    }

    bool ok = QDesktopServices::openUrl(QUrl::fromLocalFile(curPath+"/temp/"));
    if(ok){
        print_log("临时文件夹已打开", 0);
        show_tips("临时文件夹已打开");
    }else{
    }
}

/**
 * @brief 菜单栏打开公司官网（调用PC机默认浏览器）
 */
void Serial::menu_company_web()
{
    QString URL = "https://gitee.com/";
    QDesktopServices::openUrl(QUrl(URL.toLatin1()));
}

/**
 * @brief 菜单栏打开公司简介
 */
void Serial::menu_company_about()
{
    dialog_company = new DialogCompany(this);
    dialog_company->setModal(false);
    dialog_company->setWindowTitle("公司简介");
    dialog_company->show();
}

/**
 * @brief 菜单栏打开关于
 */
void Serial::menu_about_click()
{
    dialog_about = new DialogAbout(this);
    dialog_about->setModal(false);
    dialog_about->setWindowTitle("关于");
    dialog_about->show();
}

/**
 * @brief 菜单栏流量单位ML/MIN
 */
void Serial::menu_unit_flow_ML()
{
    unit_flow_ml = true;
    ui->m2_LH->setIconVisibleInMenu(false);
    ui->m2_mlmin->setIconVisibleInMenu(true);
    ui->lb_unit_flow->setText("ml/min");
    ui->lb_unit_flow1->setText("ml/min");
    ui->lb_unit_flow_show->setText("ml/min");

    ui->le_Upper_flow->setText(QString("%1").arg(obj_safe_scope.flow_upper));
    ui->le_Lower_flow->setText(QString("%1").arg(obj_safe_scope.flow_lower));

    show_tips("流量单位切换为ml/min显示");
    print_log("流量单位切换为ml/min显示",0);
}

/**
 * @brief 菜单栏流量单位L/H
 */
void Serial::menu_unit_flow_L()
{
    unit_flow_ml = false;
    ui->m2_LH->setIconVisibleInMenu(true);
    ui->m2_mlmin->setIconVisibleInMenu(false);
    ui->lb_unit_flow->setText("L/H");
    ui->lb_unit_flow1->setText("L/H");
    ui->lb_unit_flow_show->setText("L/H");

    ui->le_Upper_flow->setText(QString("%1").arg(obj_safe_scope.flow_upper*0.06));
    ui->le_Lower_flow->setText(QString("%1").arg(obj_safe_scope.flow_lower*0.06));

    show_tips("流量单位切换为L/H显示");
    print_log("流量单位切换为L/H显示",0);
}

/**
 * @brief 菜单栏温度单位℃
 */
void Serial::menu_unit_temper_SSD()
{
    unit_temper_ssd = true;
    ui->m2_ssd->setIconVisibleInMenu(true);
    ui->m2_hsd->setIconVisibleInMenu(false);

    ui->lb_unit_temper->setText("℃");
    ui->lb_unit_temper1->setText("℃");
    ui->lb_unit_temper_show->setText("℃");

    ui->le_Upper_temper->setText(QString("%1").arg(obj_safe_scope.temper_upper));
    ui->le_Lower_temper->setText(QString("%1").arg(obj_safe_scope.temper_lower));

    show_tips("温度单位切换为℃显示");
    print_log("温度单位切换为℃显示",0);
}

/**
 * @brief 菜单栏温度单位℉
 */
void Serial::menu_unit_temper_HSD()
{
    unit_temper_ssd = false;
    ui->m2_hsd->setIconVisibleInMenu(true);
    ui->m2_ssd->setIconVisibleInMenu(false);
    ui->lb_unit_temper->setText("℉");
    ui->lb_unit_temper1->setText("℉");
    ui->lb_unit_temper_show->setText("℉");

    ui->le_Upper_temper->setText(QString("%1").arg(32+obj_safe_scope.temper_upper*1.8));
    ui->le_Lower_temper->setText(QString("%1").arg(32+obj_safe_scope.temper_lower*1.8));

    show_tips("温度单位切换为℉显示");
    print_log("温度单位切换为℉显示",0);
}
/*---------------------------菜单栏设计函数(End)-------------------------------------*/

/**
 * @brief 弹出框
 * @param msgbox指针
 * @param title标题
 * @param tips提示内容
 * @param type提示类型  1--ok/cancel   2--ok
 */
void Serial::msgboxcreate(QMessageBox *msgbox,QString title, QString tips, int type){
    msgbox->setWindowTitle(title);      //消息框标题
    msgbox->setInformativeText(tips);   //消息框提示内容
    if(type == 1){
        msgbox->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);  //消息框按钮 ok/cancel
    }else if(type == 2){
        msgbox->setStandardButtons(QMessageBox::Ok);    //消息框按钮 ok
    }
    msgbox->setDefaultButton(QMessageBox::Ok);
    msgbox->setGeometry(this->frameGeometry().x()+this->frameGeometry().width()/2-178/2,    //横坐标
                       this->frameGeometry().y()+this->frameGeometry().height()/2-116/2,    //纵坐标
                       msgbox->width()+100, //宽度
                       msgbox->height());   //高度
}
